import java.io.*;

/**
 * Recurse the specified directory, loads the java files in that directory,
 * removes everything from the it except class hierarchy information and 
 * writes it to the specified output directory.
 */
public class MDLPreProcessor
{
	private boolean recurse;
	private File tempFile;

	public MDLPreProcessor(String inDir, String outDir, boolean recurse)
		throws IOException
	{
		this.recurse = recurse;
		generate(new File(inDir), new File(outDir));
		tempFile = new File("_MDL_PREPROCESSOR_TEMP.TMP");
		if ( tempFile != null ) tempFile.delete();
	}

	private void generate(File inDir, File outDir)
		throws IOException
	{
		System.out.println("Processing :: " + inDir.getCanonicalPath());

		// create the output directory if not existing.
		if ( !outDir.exists() )
			outDir.mkdir();

		// get the list of file names in inDir.
		File[] javaFiles = getSourceFiles(inDir);

		File inFile;
		File outFile;
		for(int i = 0; i < javaFiles.length; i ++ )
		{
			inFile  = javaFiles[i];
			outFile = new File(outDir, inFile.getName());

			System.out.println("Removing comment :: " + 
			                    inFile.getCanonicalPath() );
			removeComment(inFile, tempFile);

			System.out.println("Generating :: " + outFile.getCanonicalPath() );
			generateFile(tempFile,outFile);

		}

		if ( this.recurse )
		{
			File[] dirs = getDirectories(inDir);
			File nextInDir;
			File nextOutDir;
			for(int i = 0 ; i < dirs.length; i ++ )
			{
				nextInDir = dirs[i];
				nextOutDir = new File(outDir, nextInDir.getName() );
				generate(nextInDir, nextOutDir);
			}
		}
	}


	private void generateFile(File inFile, File outFile)
		throws IOException
	{
	   // Write the logic here, to remove attribute. methods
	   // and keep the innerclasses.
		BufferedReader rd = new BufferedReader(new FileReader(inFile));
		BufferedWriter wt = new BufferedWriter(new FileWriter(outFile));

		boolean done = false;
		String readLine;
		String writeLine;

		comment = false;
		while(!done)
		{
		   try
		   {
		      readLine = rd.readLine();
		      if ( readLine == null )
		        done = true;

		      if (  ( readLine != null ) &&
		            ( readLine.equals("") )
		         )
		      {
		         wt.write(readLine);
		         wt.newLine();
		      }
		      else
		      {

		         writeLine = processLine(readLine);
		         if ( writeLine != null )
		         {
		            if ( !writeLine.equals("") )
		            {
		               wt.write(writeLine, 0, writeLine.length());
		               wt.newLine();
		            }
		         }
		      }
		   }
		   catch(IOException e)
		   {
		      done = true;
		   }
		}

		try { wt.close(); } catch(IOException e1){}
		try { rd.close(); } catch(IOException e2){}
	}

	private void removeComment(File inFile, File outFile)
		throws IOException
	{
		BufferedReader rd = new BufferedReader(new FileReader(inFile));
		BufferedWriter wt = new BufferedWriter(new FileWriter(outFile));

		boolean done = false;
		String readLine;
		String writeLine;

		comment = false;
		while(!done)
		{
		   try
		   {
		      readLine = rd.readLine();
		      if ( readLine == null )
		        done = true;

		      if (  ( readLine != null ) &&
		            ( readLine.equals("") )
		         )
		      {
		         wt.write(readLine);
		         wt.newLine();
		      }
		      else
		      {

		         writeLine = processLine(readLine);
		         if ( writeLine != null )
		         {
		            if ( !writeLine.equals("") )
		            {
		               wt.write(writeLine, 0, writeLine.length());
		               wt.newLine();
		            }
		         }
		      }
		   }
		   catch(IOException e)
		   {
		      done = true;
		   }
		}

		try { wt.close(); } catch(IOException e1){}
		try { rd.close(); } catch(IOException e2){}
	}

	private boolean comment;
	private String processLine(String inLine)
	{
	    //System.out.println("Prcessing " + inLine );
	    if ( inLine == null ) return inLine;

	   int cEnd;
	   int cStart;
	   int cLine;
	   String outLine = null;
	   String outLine1 = null;

	   cEnd   = inLine.indexOf("*/");
	   cStart = inLine.indexOf("/*");
	   cLine  = inLine.indexOf("//");

	   if ( comment )
	   {
	      if ( cEnd != -1 )
	      {
	         // process the remaining line.
	         comment = false;
	         outLine = 
	          processLine(inLine.substring(cEnd + 2, inLine.length()));
	      }
	   }
	   else // start else OF if (comment)
	   {
	      if ( ( cLine == -1 ) && ( cStart == -1 ) )
	      {
	        outLine = inLine;
	        return outLine;
	      }

	      // either /* or // in the line.

	      if ( cLine == -1 )
	      {
	         ///* in the line.
	         // because cStart != -1
	         comment = true;
	         outLine  = inLine.substring(0, cStart);
	         outLine1 = 
	            processLine(inLine.substring(cStart+2, inLine.length()));

	         if ( outLine1 != null )
	           outLine = outLine + outLine1;
	      }

	      if ( cStart == -1 )
	      {
	         // // in the line.
	         // trash the line after //
	         outLine = inLine.substring(0, cLine);
	      }

	      if ( ( cStart != -1 ) && ( cLine != -1 ) )
	      {
	         // both // and /* in the line.

	         if ( cLine < cStart )
	         {
	            outLine = inLine.substring(0, cLine);
	         }
	         else
	         {
	            comment = true;
	            outLine  = inLine.substring(0, cStart);
	            outLine1 = 
	              processLine(inLine.substring(cStart+2,inLine.length()));

	            if ( outLine1 != null ) 
	              outLine = outLine + outLine1;
	         }
	      }

	   } // end else OF if ( comment )

	   return outLine;
	} // end processLine

	private File[] getSourceFiles(File directory)
	{
		String[] allFiles = directory.list(javaFilter);
		File[] javaFiles = new File[allFiles.length];
		for(int i = 0; i < allFiles.length; i ++ )
			javaFiles[i] = new File(directory, allFiles[i]);

		return javaFiles;
	}

	private File[] getDirectories(File directory)
	{
		String[] allDir = directory.list(dirFilter);
		File[] dirs = new File[allDir.length];
		for( int i = 0; i < allDir.length; i ++ )
			dirs[i] = new File(directory, allDir[i]);
		
		return dirs;
	}

	private DirFileFilter dirFilter = new DirFileFilter();
	private JavaFileFilter javaFilter = new JavaFileFilter();

	class JavaFileFilter implements FilenameFilter
	{
		public boolean accept(File dir, String fileName)
		{
			File tmpFile = new File(dir, fileName);
			if ( tmpFile.isFile() && (fileName.indexOf(".java") != -1 ))
				return true;
			else
				return false;
		}
	}

	class DirFileFilter implements FilenameFilter
	{
		public boolean accept(File dir, String fileName)
		{
			File tmpFile = new File(dir, fileName);
			return  tmpFile.isDirectory(); 
		}
	}

	public static void main(String[] args)
		throws IOException
	{
		if ( args.length < 2 ) 
		{
		   System.out.println("Usage :: java MDLPreProcessor <sourcedir> <destinationdir>");
		   System.out.println();
		   System.out.println("<sourcedir>       -  Directory where the java files are located (recurses the directory)");
		   System.out.println();
		   System.out.println("<destinationdir>  -  Directory where the processed java files are to be stored. (retains the source directory structure)");
		   System.out.println();
		   System.out.println();
		   System.out.println("MDLPreProcessor removes all the attributes and methods from the java files contained in the specified directory. It thus keeps only the Hierarchy Information intact. The processed files are written in the destination directory");
         return;
		}

		new MDLPreProcessor(args[0], args[1], true);
	}
}
